home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / GUSI 1.4.1 / GUSI / GUSIPPC.cp < prev    next >
Encoding:
Text File  |  1994-05-01  |  15.3 KB  |  794 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIPPC.cp        -    PPC Sockets
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: GUSIPPC.cp,v $
  8. Revision 1.2  1994/05/01  23:30:32  neeri
  9. Enable recvfrom with non-NULL from address.
  10.  
  11. Revision 1.1  1994/02/25  02:30:02  neeri
  12. Initial revision
  13.  
  14. Revision 0.13  1993/12/30  00:00:00  neeri
  15. Fiddle with select()
  16.  
  17. Revision 0.12  1993/09/01  00:00:00  neeri
  18. Throw out nonbreaking spaces
  19.  
  20. Revision 0.11  1993/06/20  00:00:00  neeri
  21. Changed sa_constr_ppc
  22.  
  23. Revision 0.10  1993/02/07  00:00:00  neeri
  24. New configuration technique
  25.  
  26. Revision 0.9  1992/12/17  00:00:00  neeri
  27. Forgot to clear errno in PPCSocketDomain::socket()
  28.  
  29. Revision 0.8  1992/12/06  00:00:00  neeri
  30. Check flags
  31.  
  32. Revision 0.7  1992/09/13  00:00:00  neeri
  33. Always complete write
  34.  
  35. Revision 0.6  1992/09/07  00:00:00  neeri
  36. Implement ioctl()
  37.  
  38. Revision 0.5  1992/08/30  00:00:00  neeri
  39. Move hasPPC here
  40.  
  41. Revision 0.4  1992/08/10  00:00:00  neeri
  42. Correct select()
  43.  
  44. Revision 0.3  1992/08/03  00:00:00  neeri
  45. Introduce additional buffering
  46.  
  47. Revision 0.2  1992/08/03  00:00:00  neeri
  48. Approximately correct, except for sync/async
  49.  
  50. Revision 0.1  1992/08/02  00:00:00  neeri
  51. Put some further work in
  52.  
  53. *********************************************************************/
  54.  
  55. #include "GUSIPPC_P.h"
  56.  
  57. #include <Errors.h>
  58. #include <ADSP.h>
  59. #include <Devices.h>
  60. #include <GestaltEqu.h>
  61. #include <PLStringFuncs.h>
  62.  
  63. class PPCSocket;                             // That's what this file's all about
  64.  
  65. struct PPCPB {
  66.     PPCParamBlockRec    ppc;
  67.     PPCSocket *            sock;
  68. };
  69.  
  70. class PPCSocket : public Socket    {        
  71.     friend class PPCSocketDomain;    
  72.     friend pascal void PPCReadHellHound(PPCPB * pb);
  73.     friend pascal void PPCWriteHellHound(PPCPB * pb);
  74.  
  75.     enum {
  76.         notBound, 
  77.         notOpen,
  78.         isListening,
  79.         isOpen,
  80.         isAccepted}        status;
  81.     Boolean                nonblocking;
  82.     Boolean                readPending;
  83.     Boolean                writePending;
  84.     Boolean                readShutDown;
  85.     Boolean                writeShutDown;
  86.     LocationNameRec    location;
  87.     PPCPortRec            port;
  88.     LocationNameRec    peerLoc;
  89.     PPCPortRec            peerPort;
  90.     PPCPB                    pb;
  91.     PPCPB    *                rpb;
  92.     RingBuffer *        rb;
  93.     RingBuffer *        wb;
  94.     
  95.                     PPCSocket();
  96.                     PPCSocket(const PPCSocket & acceptFrom);
  97.                     
  98.     virtual         ~PPCSocket();
  99.     
  100.     int            Alloc();
  101.     void            HellHoundsOnMyTrail();
  102. public:
  103.     virtual int    bind(void * name, int namelen);
  104.     virtual int getsockname(void * name, int * namelen);
  105.     virtual int getpeername(void *name, int *namelen);
  106.     virtual int    fcntl(unsigned int cmd, int arg);
  107.     virtual int listen(int qlen);
  108.     virtual int connect(void * address, int addrlen);
  109.     virtual Socket * accept(void * address, int * addrlen);
  110.     virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  111.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  112.     virtual int shutdown(int how);
  113.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  114.     virtual int    ioctl(unsigned int request, void *argp);
  115. };    
  116.  
  117. PPCSocketDomain    PPCSockets;
  118.  
  119. /************************ PPC Toolbox initialization ************************/
  120.  
  121. pascal OSErr PPCInit_P()
  122. {
  123.     OSErr        err;
  124.     long        attr;
  125.         
  126.     if (err = Gestalt(gestaltPPCToolboxAttr, &attr))
  127.         return err;
  128.         
  129.     if (!(attr & gestaltPPCSupportsRealTime))
  130.         err = PPCInit();
  131.  
  132.     return err;
  133. }
  134.  
  135. Feature hasPPC(PPCInit_P);
  136.  
  137. /********************* Link stuffing procedures *********************/
  138.  
  139. #pragma segment GUSIResident
  140.  
  141. pascal void PPCReadHellHound(PPCPB * pb)
  142. {
  143.     if (!pb->sock->rb)                                    // We're closing
  144.         return;
  145.         
  146.     RingBuffer &     buf     =    *pb->sock->rb;
  147.     PPCReadPBRec & p         =    pb->ppc.readParam;
  148.     Boolean &        pend    =    pb->sock->readPending;
  149.     
  150.     if (buf.Locked())
  151.         buf.Later(Deferred(PPCReadHellHound), pb);
  152.     else    {
  153.         buf.Later(nil, nil);
  154.         if (pend) {
  155.             pend    =    false;
  156.             
  157.             if (p.ioResult)    {
  158.                 pb->sock->readShutDown    =    true;
  159.                 
  160.                 return;
  161.             }
  162.             
  163.             buf.Validate(p.actualLength);
  164.         }
  165.         
  166.         if (!buf.Free()) 
  167.             buf.Later(Deferred(PPCReadHellHound), pb);
  168.         else {
  169.             long    max    =    1000000;
  170.             
  171.             p.ioCompletion    =    PPCCompProcPtr(PPCReadHellHound);
  172.             p.bufferPtr        =    buf.Producer(max);
  173.             p.bufferLength    =    max;
  174.             pend                =    true;
  175.             
  176.             PPCReadAsync(&p);
  177.         }
  178.     }
  179. }
  180.  
  181. pascal void PPCWriteHellHound(PPCPB * pb)
  182. {
  183.     if (!pb->sock->wb)                                    // We're closing
  184.         return;
  185.         
  186.     RingBuffer &      buf     =    *pb->sock->wb;
  187.     PPCWritePBRec & p         =    pb->ppc.writeParam;
  188.     Boolean &         pend    =    pb->sock->writePending;
  189.     
  190.     if (buf.Locked())
  191.         buf.Later(Deferred(PPCWriteHellHound), pb);
  192.     else    {
  193.         buf.Later(nil, nil);
  194.         
  195.         if (pend) {
  196.             pend    =    false;
  197.             
  198.             if (p.ioResult)    {
  199.                 pb->sock->writeShutDown    =    true;
  200.                 
  201.                 return;
  202.             }
  203.  
  204.             buf.Invalidate(p.actualLength);
  205.         }
  206.         
  207.         if (!buf.Valid()) 
  208.             buf.Later(Deferred(PPCWriteHellHound), pb);
  209.         else {
  210.             long    max    =    1000000;
  211.             
  212.             p.ioCompletion    =    PPCCompProcPtr(PPCWriteHellHound);
  213.             p.bufferPtr        =    buf.Consumer(max);
  214.             p.bufferLength    =    max;
  215.             p.more            =    false;
  216.             p.userData        =    0;
  217.             p.blockCreator    =    'GU∑I';
  218.             p.blockType        =    'GU∑I';
  219.             pend                =    true;
  220.             
  221.             PPCWriteAsync(&p);
  222.         }
  223.     }
  224. }
  225.  
  226. #pragma segment GUSI
  227.  
  228. /************************ PPCSocket members ************************/
  229.  
  230. PPCSocket::PPCSocket()
  231. {
  232.     status            =    PPCSocket::notBound;
  233.     nonblocking        =    false;
  234.     pb.sock            =    this;
  235.     rpb                =    nil;
  236.     rb                    =    nil;
  237.     wb                    =    nil;
  238.     readPending        =    false;
  239.     writePending    =    false;
  240.     readShutDown    =    false;
  241.     writeShutDown    =    false;
  242. }
  243.  
  244. PPCSocket::PPCSocket(const PPCSocket & acceptFrom)
  245. {
  246.     status            =    PPCSocket::isAccepted;
  247.     nonblocking        =    acceptFrom.nonblocking;
  248.     pb.ppc            =    acceptFrom.pb.ppc;
  249.     pb.sock            =    this;
  250.     rpb                =    nil;
  251.     rb                    =    nil;
  252.     wb                    =    nil;
  253.     readPending        =    false;
  254.     writePending    =    false;
  255.     readShutDown    =    false;
  256.     writeShutDown    =    false;
  257.     location            =    acceptFrom.location;
  258.     port                =    acceptFrom.port;
  259.     peerLoc            =    acceptFrom.peerLoc;
  260.     peerPort            =    acceptFrom.peerPort;
  261. }
  262.  
  263. PPCSocket::~PPCSocket()
  264. {
  265.     if (rb)    {
  266.         delete rb;
  267.         
  268.         rb = nil;
  269.     }
  270.     
  271.     if (wb)    {
  272.         delete wb;
  273.         
  274.         wb = nil;
  275.     }
  276.  
  277.     switch (status) {
  278.     case PPCSocket::isAccepted:
  279.         PPCEndSync(&pb.ppc.endParam);
  280.         
  281.         break;                                        // Don't close the port
  282.     case PPCSocket::isListening:
  283.     case PPCSocket::isOpen:
  284.         PPCEndSync(&pb.ppc.endParam);
  285.  
  286.         /* Fall through */
  287.     case PPCSocket::notOpen:
  288.         PPCCloseSync(&pb.ppc.closeParam);
  289.         /* Fall through */
  290.     case PPCSocket::notBound:
  291.         break;
  292.     }
  293. }
  294.  
  295. int PPCSocket::Alloc()
  296. {
  297.     if (!rpb)
  298.         rpb    =    new PPCPB;
  299.     
  300.     if (!rpb)
  301.         goto error;
  302.     
  303.     rpb->sock    =    this;
  304.     
  305.     if (!rb)
  306.         rb    =    new RingBuffer(2048);
  307.     
  308.     if (!rb)    
  309.         goto error;
  310.     if (!*rb)
  311.         goto errRB;
  312.     
  313.     if (!wb)
  314.         wb =    new RingBuffer(2048);
  315.     
  316.     if (!wb)    
  317.         goto errRB;
  318.     if (!*wb)
  319.         goto errWB;
  320.     
  321.     return 0;
  322.  
  323. errWB:
  324.     delete wb;
  325.     
  326.     wb    =    nil;
  327. errRB:
  328.     delete rb;
  329.     
  330.     rb    =    nil;
  331. error:
  332.     return GUSI_error(ENOMEM);
  333. }
  334.  
  335. void PPCSocket::HellHoundsOnMyTrail()
  336. {
  337.     rpb->ppc.readParam.sessRefNum        =    pb.ppc.startParam.sessRefNum;
  338.     
  339.     PPCReadHellHound(rpb);
  340.     PPCWriteHellHound(&pb);
  341. }
  342.  
  343. int PPCSocket::fcntl(unsigned int cmd, int arg)
  344. {
  345.     switch (cmd)    {
  346.     case F_GETFL:
  347.         if (nonblocking)
  348.             return FNDELAY;
  349.         else
  350.             return 0;
  351.     case F_SETFL:
  352.         if (arg & FNDELAY)
  353.             nonblocking = true;
  354.         else
  355.             nonblocking = false;
  356.             
  357.         return 0;
  358.     default:
  359.         return GUSI_error(EOPNOTSUPP);
  360.     }
  361. }
  362.  
  363. int PPCSocket::ioctl(unsigned int request, void *argp)
  364. {
  365.     switch (request)    {
  366.     case FIONBIO:
  367.         nonblocking    =    (Boolean) *(long *) argp;
  368.         
  369.         return 0;
  370.     case FIONREAD:
  371.         switch(status)    {
  372.         case PPCSocket::isAccepted:
  373.         case PPCSocket::isOpen:
  374.             break;
  375.         default:
  376.             return GUSI_error(ENOTCONN);    
  377.         }
  378.     
  379.         *(unsigned long *) argp    = rb->Valid();
  380.         
  381.         return 0;
  382.     default:
  383.         return GUSI_error(EOPNOTSUPP);
  384.     }
  385. }
  386.  
  387. int PPCSocket::bind(void *sa_name, int)
  388. {
  389.     struct sockaddr_ppc *    addr = (struct sockaddr_ppc *) sa_name;
  390.     
  391.     if (addr->family != AF_PPC)
  392.         GUSI_error(EAFNOSUPPORT);
  393.         
  394.     if (status != PPCSocket::notBound)
  395.         return GUSI_error(EINVAL);
  396.     
  397.     location = addr->location;
  398.     port        = addr->port;
  399.     
  400.     pb.ppc.openParam.ioCompletion        =    nil;
  401.     pb.ppc.openParam.serviceType        =    ppcServiceRealTime;
  402.     pb.ppc.openParam.resFlag            =    0;
  403.     pb.ppc.openParam.portName            =    &port;
  404.     pb.ppc.openParam.locationName        =    &location;
  405.     pb.ppc.openParam.networkVisible    =    true;
  406.     
  407.     switch (PPCOpenSync(&pb.ppc.openParam))    {
  408.     case noErr:
  409.         break;
  410.     case nameTypeErr:
  411.     case badReqErr:
  412.     case badPortNameErr:
  413.     case badLocNameErr:
  414.         return GUSI_error(EINVAL);
  415.     case noGlobalsErr:
  416.         return GUSI_error(ENOMEM);
  417.     case portNameExistsErr:
  418.     case nbpDuplicate:
  419.         return GUSI_error(EADDRINUSE);
  420.     default:
  421.         return GUSI_error(EFAULT);
  422.     }
  423.     
  424.     status =    PPCSocket::notOpen;
  425.     
  426.     return 0;
  427. }
  428.  
  429. int PPCSocket::getsockname(void *name, int *namelen)
  430. {
  431.     struct sockaddr_ppc    addr;
  432.     
  433.     addr.family            =    AF_PPC;
  434.     addr.location        =    location;
  435.     addr.port            =    port;
  436.     
  437.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(struct sockaddr_ppc)));
  438.     
  439.     return 0;
  440. }
  441.  
  442. int PPCSocket::getpeername(void *name, int *namelen)
  443. {
  444.     struct sockaddr_ppc    addr;
  445.     
  446.     addr.family            =    AF_PPC;
  447.     addr.location        =    peerLoc;
  448.     addr.port            =    peerPort;
  449.     
  450.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(struct sockaddr_ppc)));
  451.     
  452.     return 0;
  453. }
  454.  
  455. int PPCSocket::listen(int)
  456. {    
  457.     switch (status)    {
  458.     case PPCSocket::notBound:
  459.         return GUSI_error(EINVAL);
  460.     case PPCSocket::isOpen:
  461.     case PPCSocket::isListening:
  462.         return GUSI_error(EISCONN);
  463.     default:
  464.         break;
  465.     }
  466.     
  467.     pb.ppc.informParam.autoAccept        =    true;
  468.     pb.ppc.informParam.portName            = &peerPort;
  469.     pb.ppc.informParam.locationName     = &peerLoc;
  470.     pb.ppc.informParam.userName            =    nil;
  471.     
  472.     if (PPCInformAsync(&pb.ppc.informParam))
  473.         return GUSI_error(EINVAL);
  474.         
  475.     status = PPCSocket::isListening;
  476.     
  477.     return 0;
  478. }
  479.  
  480. int PPCSocket::connect(void *sa_name, int)
  481. {
  482.     Boolean                         guest;
  483.     struct sockaddr_ppc *    addr = (struct sockaddr_ppc *) sa_name;
  484.     Str32                            uname;
  485.     
  486.     switch (status)    {
  487.     case PPCSocket::notBound:
  488.         return GUSI_error(EINVAL);
  489.     case PPCSocket::isOpen:
  490.     case PPCSocket::isListening:
  491.     case PPCSocket::isAccepted:
  492.         return GUSI_error(EISCONN);
  493.     default:
  494.         break;
  495.     }
  496.     
  497.     if (Alloc())
  498.         return -1;
  499.  
  500.     if (addr->family != AF_PPC)
  501.         GUSI_error(EAFNOSUPPORT);
  502.     
  503.     peerLoc    = addr->location;
  504.     peerPort    = addr->port;
  505.     uname[0] = 0;
  506.         
  507.     pb.ppc.startParam.serviceType        =    ppcServiceRealTime;
  508.     pb.ppc.startParam.resFlag            =    0;
  509.     pb.ppc.startParam.portName            = &peerPort;
  510.     pb.ppc.startParam.locationName     = &peerLoc;
  511.     pb.ppc.startParam.userData            =    0;
  512.     
  513.     if (StartSecureSession(&pb.ppc.startParam, uname, true, true, &guest, "\p"))
  514.         return GUSI_error(EINVAL);
  515.         
  516.     status                                     =     PPCSocket::isOpen;
  517.     
  518.     HellHoundsOnMyTrail();
  519.     
  520.     return 0;
  521. }
  522.  
  523. Socket * PPCSocket::accept(void * address, int * addrlen)
  524. {
  525.     PPCSocket    *    newsock;
  526.     
  527.     if (status != PPCSocket::isListening)
  528.         return (Socket *) GUSI_error_nil(ENOTCONN);
  529.  
  530.     if (nonblocking && pb.ppc.informParam.ioResult == 1)
  531.         return (Socket *) GUSI_error_nil(EWOULDBLOCK);
  532.         
  533.     SPINP(pb.ppc.informParam.ioResult == 1, SP_MISC, 0);
  534.  
  535.     if (pb.ppc.informParam.ioResult)
  536.         return (Socket *) GUSI_error_nil(EFAULT);
  537.     
  538.     newsock    =    new PPCSocket(*this);
  539.  
  540.     if (!newsock)
  541.         return (Socket *) GUSI_error_nil(ENOMEM);
  542.         
  543.     if (newsock->Alloc())    {
  544.         delete newsock;
  545.         
  546.         return (Socket *) GUSI_error_nil(ENOMEM);
  547.     }
  548.     
  549.     newsock->HellHoundsOnMyTrail();
  550.                                                     
  551.     if (address && addrlen)
  552.         getpeername(address, addrlen);
  553.  
  554.     pb.ppc.informParam.autoAccept        =    true;
  555.     pb.ppc.informParam.portName        = &peerPort;
  556.     pb.ppc.informParam.locationName     = &peerLoc;
  557.     pb.ppc.informParam.userName        =    nil;
  558.     
  559.     PPCInformAsync(&pb.ppc.informParam);
  560.         
  561.     return newsock;
  562. }
  563.  
  564. int PPCSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen)
  565. {
  566.     long    len    =    buflen;
  567.     
  568.     if (from)
  569.         getpeername(from, fromlen);
  570.     if (flags)
  571.         return GUSI_error(EOPNOTSUPP);
  572.     
  573.     switch(status)    {
  574.     case PPCSocket::isAccepted:
  575.     case PPCSocket::isOpen:
  576.         break;
  577.     default:
  578.         return GUSI_error(ENOTCONN);    
  579.     }
  580.     
  581.     if (!rb->Valid())    
  582.         if (readShutDown)
  583.             return 0;
  584.         else if (nonblocking)
  585.             return GUSI_error(EWOULDBLOCK);
  586.         else
  587.             SPIN(!rb->Valid(), SP_STREAM_READ, 0);
  588.     
  589.     rb->Consume(Ptr(buffer), len);
  590.     
  591.     return len;
  592. }
  593.  
  594. int PPCSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  595. {
  596.     long    len    =    buflen;
  597.     long    done    =    0;
  598.     
  599.     if (to)
  600.         return GUSI_error(EOPNOTSUPP);
  601.     if (flags)
  602.         return GUSI_error(EOPNOTSUPP);
  603.     
  604.     switch(status)    {
  605.     case PPCSocket::isAccepted:
  606.     case PPCSocket::isOpen:
  607.         break;
  608.     default:
  609.         return GUSI_error(ENOTCONN);    
  610.     }
  611.     
  612.     if (writeShutDown)
  613.         return GUSI_error(ESHUTDOWN);
  614.     
  615.     if (!wb->Free())
  616.         if (nonblocking)
  617.             return GUSI_error(EWOULDBLOCK);
  618.         
  619.     for (;;) {
  620.         wb->Produce(Ptr(buffer), len);
  621.         
  622.         done        +=    len;
  623.         
  624.         if (nonblocking)
  625.             break;
  626.         
  627.         buflen    -=    int(len);
  628.         
  629.         if (!buflen)
  630.             break;
  631.         
  632.         buffer     =    Ptr(buffer) + len;
  633.         len        =    buflen;
  634.         
  635.         SPIN(!wb->Free(), SP_STREAM_WRITE, 0);
  636.     }
  637.     
  638.     return done;
  639. }
  640.  
  641. int PPCSocket::shutdown(int how)
  642. {
  643.     if (how < 0 || how > 2)
  644.         return GUSI_error(EINVAL);
  645.     
  646.     if (how)
  647.         writeShutDown    =    true;
  648.     if (!(how & 1))
  649.         readShutDown    =    true;
  650.         
  651.     return 0;
  652. }
  653.  
  654. int PPCSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
  655. {
  656.     int    goodies     =     0;
  657.     
  658.     if (canRead)
  659.         switch (status) {
  660.         case PPCSocket::isListening:
  661.             if (pb.ppc.informParam.ioResult != 1) {
  662.                 *canRead =     true;
  663.                 ++goodies;
  664.             }
  665.             break;
  666.         case PPCSocket::isAccepted:
  667.         case PPCSocket::isOpen:
  668.             if (rb->Valid() || readShutDown) {
  669.                 *canRead =     true;
  670.                 ++goodies;
  671.             } 
  672.             break;
  673.         default:
  674.             *canRead =     true;
  675.             ++goodies;
  676.             break;
  677.         }
  678.     
  679.     if (canWrite)
  680.         switch (status) {
  681.         case PPCSocket::isAccepted:
  682.         case PPCSocket::isOpen:
  683.             if (wb->Free()) {
  684.                 *canWrite = true;
  685.                 ++goodies;
  686.             }
  687.             break;
  688.         default:
  689.             *canWrite = true;
  690.             ++goodies;
  691.             break;
  692.         }
  693.     
  694.     return goodies;
  695. }
  696.  
  697. /********************* PPCSocketDomain member **********************/
  698.  
  699. extern "C" void GUSIwithPPCSockets()
  700. {
  701.     PPCSockets.DontStrip();
  702. }
  703.  
  704. PPCSocketDomain::PPCSocketDomain()
  705.     :    SocketDomain(AF_PPC)    
  706. {
  707. }
  708.  
  709. Socket * PPCSocketDomain::socket(int type, short)
  710. {
  711.     PPCSocket * sock    =    nil;
  712.     
  713.     errno = 0;
  714.     
  715.     if (!hasPPC)
  716.         GUSI_error(EOPNOTSUPP);
  717.     else 
  718.         switch (type)    {
  719.         case SOCK_STREAM:
  720.             sock = new PPCSocket();
  721.             break;
  722.         default:
  723.             GUSI_error(ESOCKTNOSUPPORT);
  724.         }    
  725.     
  726.     if (sock && errno)    {
  727.         delete sock;
  728.         
  729.         return nil;
  730.     } else
  731.         return sock;
  732. }
  733.  
  734. static sa_constr_ppc *    CurConstr;
  735.  
  736. static pascal Boolean GUSIBrowseFilter(LocationNamePtr, PortInfoPtr port)
  737. {
  738.     if (CurConstr->flags & PPC_CON_MATCH_NAME)
  739.         if (PLstrcmp(port->name.name, CurConstr->match.name))
  740.             return false;
  741.     if (CurConstr->flags & PPC_CON_MATCH_TYPE)
  742.         if (port->name.portKindSelector != ppcByString || PLstrcmp(port->name.u.portTypeStr, CurConstr->match.u.portTypeStr))
  743.             return false;
  744.     
  745.     return true;
  746. }
  747.  
  748. int PPCSocketDomain::choose(int, char * prompt, void * constraint, int flags, void * name, int * namelen)
  749. {
  750.     sockaddr_ppc            addr;
  751.     char *                    end;
  752.     Str255                    promp;
  753.     StringPtr                nbp    = nil;
  754.     PortInfoRec                info;
  755.     static sa_constr_ppc constr;
  756.     
  757.     if (flags & (CHOOSE_NEW | CHOOSE_DIR))
  758.         return GUSI_error(EINVAL);
  759.         
  760.     end         =     (char *) memccpy(promp+1, prompt, 0, 254);
  761.     promp[0]    =    end-(char *)promp-2;
  762.     CurConstr=    (sa_constr_ppc *) constraint;
  763.     
  764.     if (!CurConstr || !(CurConstr->flags & PPC_CON_NEWSTYLE)) {
  765.         if (CurConstr && ((char *) constraint)[0]) {
  766.             constr.flags    =    PPC_CON_NEWSTYLE + PPC_CON_MATCH_NBP;
  767.             nbp                =    StringPtr(constraint);
  768.         } else
  769.             constr.flags     =    PPC_CON_NEWSTYLE;
  770.         
  771.         CurConstr    =    &constr;
  772.     } else if (CurConstr->flags & PPC_CON_MATCH_NBP)
  773.         nbp = CurConstr->nbpType;
  774.     
  775.     if (
  776.         PPCBrowser(
  777.             promp, 
  778.             "\p", 
  779.             false, 
  780.             &addr.location, 
  781.             &info, 
  782.             (CurConstr->flags & (PPC_CON_MATCH_NAME | PPC_CON_MATCH_TYPE)) ? &GUSIBrowseFilter : PPCFilterProcPtr(nil),
  783.             nbp ? nbp : "\pPPCToolBox")
  784.     )
  785.         return GUSI_error(EINTR);
  786.  
  787.     addr.family    =    AF_PPC;
  788.     addr.port    =    info.name;
  789.     
  790.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(sockaddr_ppc)));
  791.     
  792.     return 0;
  793. }
  794.